package tichu_project252;

import java.util.Collections;
import java.util.LinkedList;
import tichu_project252.CardClasses.*;
import tichu_project252.Model.Model;
import tichu_project252.Round.TurnType;

/**
 * Implements the players' entity.
 *
 * <p> <b> Invariants: </b> </p>
 *
 * @author Alexandra Barka, ΑΜ: 2867, login : barka.
 * @author Euaggelia Petauraki AM: 2875 login: petavraki.
 * @version %I%, %G%
 *
 */
public class Player {

    private String name; //the name of the player
    private LinkedList<Card> hand; //the hand of the player
    private LinkedList<Card> trick; // the trick of the player
    private boolean tichu; //if the player said tichu
    private boolean grandTichu; //if the player said grand tichu
    private int score; // the score of the player
    private Player teammate; //the teammate of the player
    private boolean pass; //if player said pass
    private boolean first = false;

    /**
     * Constructs a new player.
     *
     * <p><b>Constructor: </b>Player(String name)</p>
     *
     * <p><b>Precondition: </b> The name isn't null</p> <p><b>Postcondition:
     * </b> Constructs a new valid player </p>
     *
     * @throws Exception if a mistake occures
     */
    public Player(String name) throws Exception {
        hand = new LinkedList<Card>();
        trick = new LinkedList<Card>();
        if (name != null) {
            this.name = name;
            this.score = 0;
        } else {
            throw new Exception("You gave a null name");
        }
    }

    /**
     * Sets if player said pass. <p><b>Transformer(mutator):</b> setPass(boolean
     * pass)</p>
     *
     * <p><b>Precondition: </b></p> <p><b>Postcondition: </b>sets pass </p>
     *
     * @param pass if player said pass or not
     */
    public void setPass(boolean pass) {
        this.pass = pass;
    }

    /**
     * Returns if the player said pass.
     *
     * <p> <b> Accessor: </b> getPass() </p>
     *
     * <p><b> Precondition: </b> </p> <p> <b> Postcondition:</b> Returns if the
     * player said pass. </p>
     *
     * @return if the player said pass
     */
    public boolean getPass() {
        return pass;
    }

    /**
     * Sets if player said tichu. <p><b>Transformer(mutator):</b>
     * setTichu(boolean tichu)</p>
     *
     * <p><b>Precondition: </b></p> <p><b>Postcondition: </b>sets tichu </p>
     *
     * @param tichu if player said tichu or not
     */
    public void setTichu(boolean tichu) {
        this.tichu = tichu;
    }

    /**
     * Returns if the player said tichu.
     *
     * <p> <b> Accessor: </b> getTichu() </p>
     *
     * <p><b> Precondition: </b> </p> </p> <p> <b> Postcondition:</b> Returns if
     * the player said tichu. </p>
     *
     * @return if the player said tichu
     */
    public boolean getTichu() {
        return tichu;
    }

    /**
     * Sets if player said grand tichu. <p><b>Transformer(mutator):</b>
     * setGrandTichu(boolean grandTichu)</p>
     *
     * <p><b>Precondition: </b></p> <p><b>Postcondition: </b>sets grand tichu
     * </p>
     *
     * @param grandTichu if player said grand tichu or not
     */
    public void setGrandTichu(boolean grandTichu) {
        this.grandTichu = grandTichu;
    }

    /**
     * Returns if the player said grand tichu.
     *
     * <p> <b> Accessor: </b> getGrandTichu() </p>
     *
     * <p><b> Precondition: </b> </p>
     *
     * </p> <p> <b> Postcondition:</b> Returns if the player said Grand tichu.
     * </p>
     *
     * @return if the player said Grand tichu
     */
    public boolean getGrandTichu() {
        return grandTichu;
    }

    /**
     * Returns true if player has Mahjong.
     *
     * <p> <b> Accessor(Selector): </b> hasMahjong() </p>
     *
     * <p><b> Precondition: </b> The deck shall be dealt.</p> </p> <p> <b>
     * Postcondition:</b> Returns true if the players has Mahjong else returns
     * false.. </p>
     *
     * @return true if the player has Mahjong else it returns false
     */
    public boolean hasMahjong() {
        for (int i = 0; i < hand.size(); i++) {
            if (hand.get(i) instanceof Mahjong) {
                return true;
            }
        }
        return false;
    }

    /**
     * Returns true if player has Hund.
     *
     * <p> <b> Accessor(Selector): </b> hasHund() </p>
     *
     * <p><b> Precondition: </b> The deck shall be dealt.</p> </p> <p> <b>
     * Postcondition:</b> Returns true if the players has Hund else returns
     * false.. </p>
     *
     * @return true if the player has Hund else it returns false
     */
    public boolean hasHund() {
        for (int i = 0; i < hand.size(); i++) {
            if (hand.get(i) instanceof Hund) {
                return true;
            }
        }
        return false;
    }

    /**
     * Returns true if player has Drache.
     *
     * <p> <b> Accessor(Selector): </b> hasDrache() </p>
     *
     * <p><b> Precondition: </b> The deck shall be dealt.</p> </p> <p> <b>
     * Postcondition:</b> Returns true if the players has Drache else returns
     * false.. </p>
     *
     * @return true if the player has Drache else it returns false
     */
    public boolean hasDrache() {
        for (int i = 0; i < hand.size(); i++) {
            if (hand.get(i) instanceof Drache) {
                return true;
            }
        }
        return false;
    }

    /**
     * Returns true if player has Phoenix.
     *
     * <p> <b> Accessor(Selector): </b> hasPhoenix() </p>
     *
     * <p><b> Precondition: </b> The deck shall be dealt.</p> </p> <p> <b>
     * Postcondition:</b> Returns true if the players has Phoenix else returns
     * false.. </p>
     *
     * @return true if the player has Phoenix else it returns false
     */
    public boolean hasPhoenix() {
        for (int i = 0; i < hand.size(); i++) {
            if (hand.get(i) instanceof Phoenix) {
                return true;
            }
        }
        return false;
    }

    /**
     * Returns true if player has Bomb.
     *
     * <p> <b> Accessor(Selector): </b> hasBomb() </p>
     *
     * <p><b> Precondition: </b> The deck shall be dealt.</p> </p> <p> <b>
     * Postcondition:</b> Returns true if the players has Bomb else returns
     * false.. </p>
     *
     * @return true if the player has Bomb else it returns false
     */
    public boolean hasBomb() {
        boolean flag = false;
        int[] hasBombs = new int[14];
        for (int i = 0; i < hand.size(); i++) {
            if (hand.get(i) instanceof simpleCard) {
                hasBombs[hand.get(i).getintRepr() - 2]++;
            }
        }
        for (int i = 0; i < hasBombs.length; i++) {
            if (hasBombs[i] == 4) {
                flag = true;
                break;
            }
        }
        //kenta xrwma
        return flag;
    }

    public boolean hasStreetBomb() {
        boolean flag = true;
        LinkedList<Integer> temp = new LinkedList<Integer>();
        String[] suits = {"Jade", "Sword", "Pagoda", "Star"};

        //for each suit
        for (int c = 0; c < 4; c++) {
            temp.clear();
            //add those suit's intReprs to an integer list
            System.out.println(suits[c]);
            for (int i = 0; i < hand.size(); i++) {
                if (this.hand.get(i) instanceof simpleCard) {
                    if (this.hand.get(i).getSuit().equals(suits[c])) {
                        temp.add(this.hand.get(i).getintRepr());
                    }
                }
            }
            //sort it
            Collections.sort(temp);
            System.out.println(temp);

            //if the cards are above 5, we might have a street!
            if (temp.size() >= 5) {
                int counter = 0;
                //so check them out
                for (int i = 1; i < temp.size(); i++) {
                    //if two consecutive cards have an intRepr difference
                    //count it! 
                    if (temp.get(i) - temp.get(i - 1) == 1) {
                        //we're out
                        counter++;
                        //otherwise restart the counter
                    } else {
                        //that way we'll be able to catch the street 2,{4,5,6,7,8}
                        counter = 0;
                    }
                }
                //if counter is less than 5, we keep on looking, otherwise return true
                if (counter >= 5) {
                    //e.g. {2,3,4,5,6},8
                    return true;
                } else {
                    //e.g. 2,4,5,6,7,9
                    flag = false;
                }
            } else {
                flag = false;
            }
        }

        return flag;
    }

    /**
     * Calculates the score of the specific player.
     *
     * <p> <b> Accessor(Selector): </b> hasPhoenix() </p>
     *
     * <p><b> Precondition: </b> The player has taken a trick.</p> </p> <p> <b>
     * Postcondition:</b> Returns the score of the player.. </p>
     *
     * @return the score of the specific player
     */
    public int calcScore() {
        int sum = 0;
        for (int i = 0; i < trick.size(); i++) {
            if (trick.get(i).getintRepr() == 5) {
                sum = sum + 5;
            } else if (trick.get(i).getintRepr() == 10 || trick.get(i).getintRepr() == 13) {
                sum = sum + 10;
            } else if ("Phoenix".equals(trick.get(i).getstringRepr())) {
                sum = sum - 25;
            } else if ("Drache".equals(trick.get(i).getstringRepr())) {
                sum = sum - 25;
            }
        }
        score = sum;
        /*
        //this means the player finished first
        if(first && this.grandTichu) {
            score += 200;
        } 
        //if he did not finish first and has already said gtichu
        if(!first && this.grandTichu) {
            score -= 200;
        }
        
        if(first && this.tichu) {
            score += 100;
        }
        
        if(!first && this.tichu) {
            score -= 100;
        }*/
        
        return score;
    }

    /**
     * Adds a card in the hand.
     *
     * <p> <b> Transformer(mutator): </b> add(Card card)</p>
     *
     * <p><b> Precondition: </b> The card is valid.</p> </p> <p> <b>
     * Postcondition:</b> Adds to the hand the card.. </p>
     *
     * @param card The card we want to add in the hand
     * @return true if the card is added to the list correctly
     *
     * @see <a
     * href="http://docs.oracle.com/javase/1.4.2/docs/api/java/util/LinkedList.html#add(java.lang.Object)">add</a>
     *
     */
    public boolean add(Card card) {
        return hand.add(card);
    }

    /**
     * Sets the teammate.
     *
     * <p><b>Transformer(mutator):</b> setTeammate(Player p)</p>
     *
     * <p><b>Precondition: </b>The player is valid </p> <p><b>Postcondition:
     * </b>sets the teammate of the player </p>
     *
     * @param p The teammate player
     */
    public void setTeammate(Player p) {
        this.teammate = p;
    }

    /**
     * Returns the teammate of the player.
     *
     * <p> <b> Accessor: </b> getTeammate() </p>
     *
     * <p><b> Precondition: </b> The teammate is a valid player</p>
     *
     * </p> <p> <b> Postcondition:</b> Returns the teammate. </p>
     *
     * @return The teammate of the player
     */
    public Player getTeammate() {
        return this.teammate;
    }

    /**
     * Returns if the player is still active in the game.
     *
     * If the hand.size is 0, that means that he has get rid of all his cards.
     *
     * <p> <b> Accessor(Selector): </b> isActive()</p>
     *
     * <p><b> Precondition: </b> The deck shall be dealt.</p> </p> <p> <b>
     * Postcondition:</b> Returns true if the player still has cards in his
     * hands else returns false </p>
     *
     * @return if the player is active.
     */
    public boolean isActive() {
        return !(hand.size() == 0);
    }

    /**
     * Returns the card that player has chosen to play.
     *
     * <p><b>Transformer(mutator):</b> playCards()</p>
     *
     * <p><b>Precondition: </b>The player has cards in his hand </p>
     * <p><b>Postcondition: </b> Puts in the temp list the selected cards </p>
     *
     * @return a linked list with the cards player wants to play.
     */
    public LinkedList<Card> playCards(boolean flag) {
        LinkedList<Card> temp = new LinkedList<Card>();

        for (int i = 0; i < hand.size(); i++) {
            if (hand.get(i).getSelected()) {
                temp.add(hand.get(i));
            }
        }
        if (flag) {
            hand.removeAll(temp);
        }
        return temp;
    }

    /**
     * Discards all the cards from the trick and the hand.
     *
     * <p><b>Transformer(mutator):</b> discardAll()</p>
     *
     * <p><b>Precondition: </b>The player has cards in his hand </p>
     * <p><b>Postcondition: </b> Discard all the cards from the hand and the
     * trick. </p>
     *
     * @see <a
     * href="http://docs.oracle.com/javase/1.4.2/docs/api/java/util/LinkedList.html#clear()">clear</a>
     *
     */
    public void discardAll() {
        trick.clear();
        hand.clear();
    }

    public void addAll(LinkedList<Card> l) {
        hand.addAll(l);
    }

    public LinkedList<Card> getCards() {
        return hand;
    }

    public void setTrick(LinkedList<Card> temp) {
        this.trick.addAll(temp);
    }

    public LinkedList<Card> getTrick() {
        return trick;
    }
    
    public void setFirst() { 
        this.first = true;
    }
}
